#include "stdafx.h"
#include "DisplayModes.h"
#include "Log.h"
#include "Exception.h"
#include "ErrorHandlers.h"
#include "MemUtils.h"

namespace Cvekas {

DisplayMode::DisplayMode(D3DDISPLAYMODE& mode)
	:
mode(mode)
{
}

DisplayMode::DisplayMode(const DisplayMode& display_mode)
	:
mode(display_mode.mode)
{}

DisplayMode::~DisplayMode()
{}

uint DisplayMode::getWidth()
{
	return mode.Width;
}

uint DisplayMode::getHeight()
{
	return mode.Height;
}

uint DisplayMode::getRefreshRate()
{
	return mode.RefreshRate;
}

D3DFORMAT DisplayMode::getFormat()
{
	return mode.Format;
}

D3DDISPLAYMODE DisplayMode::getD3DDisplayMode()
{
	return mode;
}

std::string DisplayMode::getDescription()
{
	return FORMAT("%dx%d %dHz", % mode.Width % mode.Height % mode.RefreshRate);
}

bool DisplayMode::operator<(const DisplayMode& d) const
{
	if(mode.Width != d.mode.Width)
		return mode.Width < d.mode.Width;
	if(mode.Height != d.mode.Height)
		return mode.Height < d.mode.Height;
	if(mode.RefreshRate != d.mode.RefreshRate)
		return mode.RefreshRate < d.mode.RefreshRate;

	return false;
}

bool DisplayMode::operator==(const DisplayMode& d) const
{
	if(mode.Width != d.mode.Width)
		return false;
	if(mode.Height != d.mode.Height)
		return false;
	if(mode.RefreshRate != d.mode.RefreshRate)
		return false;

	return true;
}

uint DisplayModes::getModeCount()
{
	return mode_count;
}

DisplayMode& DisplayModes::getMode(uint i)
{
	assert(i < mode_count);

	return modes[i];
}

uint DisplayModes::getCurrentMode()
{
	D3DDISPLAYMODE mode;
	E_E(d3d->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &mode));
	return findMode(mode.Width, mode.Height, mode.RefreshRate);
}

uint DisplayModes::getCurrentAppMode(VideoSettings& settings)
{
	uint width = settings["ScreenWidth"];
	uint height = settings["ScreenHeight"];
	uint refresh = settings["RefreshRate"];

	// If windowed..
	if(refresh == 0)
		// Choose desktop refresh rate
		refresh = modes[desktop_mode].getRefreshRate();

	return findMode(width, height, refresh);
}

uint DisplayModes::getDesktopMode()
{
	return desktop_mode;
}

uint DisplayModes::findMode(uint width, uint height, uint refresh)
{
	uint i;
	for(i = 0; i < mode_count; ++i)
	{
		if(width == modes[i].getWidth() && height == modes[i].getHeight() 
			&& refresh == modes[i].getRefreshRate())
			break;
	}

	if(i == mode_count)
		i = ~0;

	return i;
}

void DisplayModes::setMode(VideoSettings& settings, uint i)
{
	settings["ScreenWidth"] = modes[i].getWidth();
	settings["ScreenHeight"] = modes[i].getHeight();
	settings["RefreshRate"] = modes[i].getRefreshRate();
}

DisplayModes::DisplayModes(D3DPtr d3d)
: d3d(d3d)
{
	LOG("Enumerating display modes...");

	// Fill 32 bit modes
	int mode_count_32bpp = d3d->GetAdapterModeCount(D3DADAPTER_DEFAULT, D3DFMT_X8R8G8B8);
	for(int i = 0; i < mode_count_32bpp; i++)
	{
		D3DDISPLAYMODE mode;
		E_L(d3d->EnumAdapterModes(D3DADAPTER_DEFAULT, D3DFMT_X8R8G8B8, i, &mode));
		modes.push_back(DisplayMode(mode));
	}

	// Nobody uses 16 bit colors anymore...
	/*
	// Fill 16 bit modes
	int mode_count_16bpp = direct3d->GetAdapterModeCount(D3DADAPTER_DEFAULT, D3DFMT_R5G6B5);
	for(int i = 0; i < mode_count_16bpp; i++)
	{
		D3DDISPLAYMODE mode;
		E_L(d3d->EnumAdapterModes(D3DADAPTER_DEFAULT, D3DFMT_R5G6B5, i, &mode));
		modes.push_back(DisplayMode(mode));
	}
	*/

	mode_count = modes.size();
	std::sort(modes.begin(), modes.end());

	desktop_mode = getCurrentMode();

	LOG(FORMAT("Enumeration done, found %d display modes", % mode_count));
}

} // namespace